#version 450

// font data courtesy of MicroProfile (https://github.com/zeux/microprofile/blob/master/microprofiledraw.h)
// glyphs are 5x8 pixels, but we shade one more line for drop shadows
layout(local_size_x = 5, local_size_y = 9, local_size_z = 1) in;

struct TextData
{
	ivec2 offset;
	int scale;
	uint color;

	uint data[112/4];
};

layout(push_constant) uniform block
{
	TextData text;
};

layout(binding = 0) uniform writeonly image2D outImage;

// glyph U offset (0-1023) for each ASCII character (uint16), packed into uint
const uint g_MicroProfileFontDescription[256*2/4] =
{
	0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,
	0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,
	0x0ce0201,0x2090211,0x2190221,0x2290231,0x2390241,0x2490251,0x2590261,0x2690271,
	0x1b101b9,0x1c101c9,0x1d101d9,0x1e101e9,0x1f101f9,0x2790281,0x2890291,0x29902a1,
	0x2a90001,0x0090011,0x0190021,0x0290031,0x0390041,0x0490051,0x0590061,0x0690071,
	0x0790081,0x0890091,0x09900a1,0x0a900b1,0x0b900c1,0x0c902b1,0x2b902c1,0x2c902d1,
	0x0ce00d9,0x0e100e9,0x0f100f9,0x1010109,0x1110119,0x1210129,0x1310139,0x1410149,
	0x1510159,0x1610169,0x1710179,0x1810189,0x1910199,0x1a102d9,0x2e102e9,0x2f100ce,
	0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,
	0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,
	0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,
	0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,
	0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,
	0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,
	0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,
	0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,0x0ce00ce,
};

// a 1024x9 texture, packed in raster order into bits:
// each byte encodes a pixel in each bit
// offsets into this data come from font description above
const uint g_MicroProfileFont[1024*9/32] =
{
	0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
	0x10783878,0x7c7c3c44,0x38044440,0x44443878,0x3878387c,0x44444444,0x447c0000,0x40000400,
	0x18004010,0x08403000,0x00000000,0x00001000,0x00000000,0x00003810,0x387c087c,0x1c7c3838,
	0x10282810,0x00201008,0x10100000,0x00000000,0x00040020,0x38387000,0x1c10001c,0x10703000,
	0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
	0x28444444,0x40404044,0x10044840,0x6c444444,0x44444410,0x44444444,0x44040000,0x40000400,
	0x24004000,0x00401000,0x00000000,0x00001000,0x00000000,0x00004430,0x44041840,0x20044444,
	0x1028283c,0x44501010,0x08541000,0x00000400,0x00080010,0x44444040,0x04280030,0x10185800,
	0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
	0x44444044,0x40404044,0x10045040,0x54644444,0x44444010,0x44444428,0x28080038,0x783c3c38,
	0x20387830,0x1844106c,0x7838783c,0x5c3c3c44,0x44444444,0x7c004c10,0x04082878,0x40084444,
	0x10007c50,0x08500020,0x04381000,0x00000810,0x10107c08,0x08544020,0x04440030,0x10180000,
	0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
	0x44784044,0x7878407c,0x10046040,0x54544478,0x44783810,0x44445410,0x10100004,0x44404444,
	0x78444410,0x08481054,0x44444444,0x60401044,0x44442844,0x08005410,0x18184804,0x7810383c,
	0x10002838,0x10200020,0x04107c00,0x7c001000,0x00200004,0x105c4010,0x04000060,0x100c0000,
	0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
	0x7c444044,0x40404c44,0x10045040,0x444c4440,0x54500410,0x44445428,0x1020003c,0x4440447c,
	0x20444410,0x08701054,0x44444444,0x40381044,0x44541044,0x10006410,0x20047c04,0x44204404,
	0x10007c14,0x20540020,0x04381010,0x00002010,0x10107c08,0x10584008,0x04000030,0x10180000,
	0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
	0x44444444,0x40404444,0x10444840,0x44444440,0x48484410,0x44286c44,0x10400044,0x44404440,
	0x203c4410,0x08481054,0x44444444,0x4004124c,0x2854283c,0x20004410,0x40440844,0x44204408,
	0x00002878,0x44480010,0x08541010,0x00004000,0x10080010,0x00404004,0x04000030,0x10180000,
	0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
	0x44783878,0x7c403c44,0x3838447c,0x44443840,0x34443810,0x38104444,0x107c003c,0x783c3c3c,
	0x20044438,0x48443844,0x4438783c,0x40780c34,0x106c4404,0x7c003838,0x7c380838,0x38203870,
	0x10002810,0x00340008,0x10100020,0x00100000,0x20040020,0x103c7000,0x1c007c1c,0x10700000,
	0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
	0x00380000,0x30000000,0x00004004,0x00000000,0x00000038,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
};

void main()
{
	ivec2 margin = ivec2(1, 2);
	ivec2 size = ivec2(gl_WorkGroupSize.xy) + margin;
	ivec2 pos = ivec2(gl_WorkGroupID.xy) * size + ivec2(gl_LocalInvocationID.xy);

	uint char = bitfieldExtract(text.data[gl_WorkGroupID.x / 4], int(gl_WorkGroupID.x % 4) * 8, 8);
	uint offset = bitfieldExtract(g_MicroProfileFontDescription[char / 2], 16 - int(char % 2) * 16, 16);

	uint u = offset + gl_LocalInvocationID.x;
	uint v = gl_LocalInvocationID.y;
	uint texoff = u + 1024 * v;

	// sample the texture twice to get the drop shadow effect
	uint texbit0 = bitfieldExtract(g_MicroProfileFont[texoff / 32], 31 - int(texoff % 32), 1);
	uint texbit1 = v == 8 ? 0 : bitfieldExtract(g_MicroProfileFont[(texoff + 1024) / 32], 31 - int(texoff % 32), 1);

	if ((texbit0 | texbit1) == 0)
		return;

	vec3 color = texbit1 == 1 ? unpackUnorm4x8(text.color).bgr : vec3(0.0);

	for (int y = 0; y < text.scale; ++y)
		for (int x = 0; x < text.scale; ++x)
			imageStore(outImage, (text.offset * size + pos) * text.scale + ivec2(x, y), vec4(color, 1.0));
}
